package com.gfl.trivialrestclient.controllers;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import com.gfl.trivialrestclient.controllers.forms.AjaxBindingResult;
import com.gfl.trivialrestclient.controllers.forms.AjaxSubmitionStatus;
import com.gfl.trivialrestclient.controllers.forms.UserCmd;
import com.gfl.trivialrestclient.controllers.validators.UserCmdValidator;
import com.gfl.trivialrestclient.model.User;
import com.gfl.trivialrestclient.services.LoginService;
import com.gfl.trivialrestclient.services.UserService;
import com.gfl.trivialrestclient.services.UserServiceException;

@Controller
public class RegistrationController {
	private final Log log = LogFactory.getLog(getClass());

	private UserService userService;
	private LoginService loginService;

	@Autowired
	public void setLoginService(LoginService loginService) {
		this.loginService = loginService;
	}

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	@InitBinder
	public void initBinder(WebDataBinder webDataBinder) {
		UserCmdValidator userCmdValidator = new UserCmdValidator();
		userCmdValidator.setUserService(userService);

		webDataBinder.setValidator(userCmdValidator);
		webDataBinder.registerCustomEditor(String.class,
				new StringTrimmerEditor(true));
	}

	@ModelAttribute("userCmd")
	private UserCmd defaultUserCmd() {
		return new UserCmd("username", "", "", "yourmailbox@gmail.com");
	}

	@RequestMapping(value = "auth/register", method = RequestMethod.GET)
	public String registerUser(@ModelAttribute("userCmd") UserCmd userCmd,
			Model model) {
		return "auth/register";
	}

	@RequestMapping(value = "auth/register", method = RequestMethod.POST)
	public String saveRegisteredUser(@Valid UserCmd userCmd,
			BindingResult result, Model model, HttpServletRequest request,
			HttpServletResponse response) {

		if (result.hasErrors()) {
			return "auth/register";
		}

		// convert command object to user
		User user = UserCmd.buildUserFrom(userCmd);
		// save user
		userService.createUser(user);

		// autologin
		try {
			loginService.webLogin(user.getLogin(), user.getPassword(), request,
					response);
		} catch (BadCredentialsException ex) {
			// can't autologin - redirect to login form
			return "redirect:/auth/login";
		}

		String okRedirView = "redirect:/auth/okRegistered";
		return okRedirView;
	}

	public static class SomeClass {
		private String name;

		public SomeClass(String name) {

			this.name = name;
		}

		public String getName() {
			return name;
		}
	}

	@RequestMapping(value = "auth/register.json", method = RequestMethod.POST)
	public @ResponseBody
	AjaxSubmitionStatus ajaxedSaveRegisteredUser(
			@Valid @ModelAttribute("userCmd") UserCmd userCmd,
			BindingResult result, HttpServletRequest request,
			HttpServletResponse response) {

		if (result.hasErrors()) {
			AjaxSubmitionStatus errorStatus = new AjaxSubmitionStatus(
					false);
			errorStatus.setErrorMessage("Validation error");
			errorStatus.setBindingResult(new AjaxBindingResult(result));

			return errorStatus;
		}

		// convert command object to user
		User user = UserCmd.buildUserFrom(userCmd);
		// save user
		userService.createUser(user);

		// autologin
		String contextPath = request.getContextPath();
		String redirUrl = contextPath + "/auth/okRegistered";
		try {
			loginService.webLogin(user.getLogin(), user.getPassword(), request,
					response);
		} catch (BadCredentialsException ex) {
			// can't autologin - redirect to login form
			redirUrl = contextPath + "/auth/login";
		}

		AjaxSubmitionStatus okStatus = new AjaxSubmitionStatus(true);
		okStatus.setTargetUrl(redirUrl);

		return okStatus;

	}

	@RequestMapping("auth/okRegistered")
	public String okRegisteredPage() {
		return "auth/okRegistered";
	}

	@ExceptionHandler(value = { RuntimeException.class, ServletException.class,
			UserServiceException.class })
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public ModelAndView handleExceptions(Exception ex) {
		log.error("Error in RegistrationController." + ex.getClass().getName(),
				ex);

		ModelAndView mav = new ModelAndView("error");
		mav.addObject("messsage", "Can't register new user");
		return mav;
	}

}
